import { Point } from './ts-geometry-2d/Point';
import { Line } from './ts-geometry-2d/Line';

// 球
export class DeskBall {
  public position: Point = null; // 球的位置
  public index: number = 0; // 球的标号
  public score: number = 0; // 进球后获得的分值
  constructor(x: number, y: number, idx: number, s: number = 1) {
    this.position = new Point(x, y);
    this.index = idx;
    this.score = s;
  }
  setPosition(pos: Point) {
    this.position.x = pos.x;
    this.position.y = pos.y;
  }
}

// 球洞
export class DeskHole {
  static HoleWidthX = 5;
  static HoleWidthY = 3;
  public position: Point;  // 球洞外侧可以当做瞄准点的位置
  public index: number;    // 1 到 6 号球洞
  public isInHole: boolean; // 是否球洞正中间
  constructor(x: number, y: number, idx: number, isInHole: boolean = false) {
    this.position = new Point(x, y);
    this.index = idx;
    this.isInHole = isInHole;
  }
  // 是否是中洞 x 值在 0 附近
  public isMiddleHole() {
    return Math.abs(this.position.x) < DeskHole.HoleWidthX;
  }

  public isBottomHole() {
    return Math.abs(this.position.x) > DeskHole.HoleWidthX;
  }

  public isUpMiddleHole() {
    return this.isMiddleHole() && this.position.y > DeskHole.HoleWidthY;
  }
  public isDownMiddleHole() {
    return this.isMiddleHole() && this.position.y < -DeskHole.HoleWidthY;
  }
  public isLeftBottomHole() {
    return this.isBottomHole() && this.position.x < -DeskHole.HoleWidthX;
  }
  public isRightBottomHole() {
    return this.isBottomHole() && this.position.x > DeskHole.HoleWidthX;
  }
}

// 击打球的路径轨迹信息
export class HitPath {
  public static HitTypeDirect = 0; // 0 直接进洞
  public static HitTypeIndirectCollision = 1; // 1 间接碰撞进洞
  public static HitTypeReboundHoled = 2; // 2 桌面反弹解球
  public static HitTypeReboundCollision = 3; // 3 反弹碰撞
  public static HitTypeBackUp = 1000; // 兜底方案，随意爆杆

  public hitType: number; // 击球类型 0 直接进洞 1 间接碰撞进洞 2 反弹进球 3 反弹解球
  public targetPos: Point; // 击打目标位置
  public targetBall: DeskBall; // 目标球
  public targetHole: DeskHole; // 目标球洞

  public force: number;    // [完美的力度] 一般是进球最合适的力度
  public minForce: number; //【最小的力度】刚好能进球的力度
  public maxForce: number; //【最大力度】进球最大力度，过大可能会被球洞反弹回来，尤其是中洞
  public spin: Point;   // 加塞（击打母球的位置）等 y 低/中/高 x 控制 左/右

  public mainBallNextPos: Point; // 击打完成后，白球的位置
  public score: number; // 分数值[0, 1] 进球的概率值

  constructor(ht: number, target: Point, targetBall: DeskBall, targetHole: DeskHole) {
    this.hitType = ht;
    this.targetPos = target;
    this.targetBall = targetBall;
    this.targetHole = targetHole;

    this.score = 0;
    this.minForce = 0.5;
    this.force = 0.75;
    this.maxForce = 1.0;

    this.spin = new Point(0, 0);
  }
  public hasDirectHitBall() { return this.hitType === 0 || this.hitType === HitPath.HitTypeIndirectCollision || this.hitType === HitPath.HitTypeReboundHoled; }
  public isDirectHitBall() { return this.hitType === 0; }
  public setScore(s: number) {
    this.score = s;
  }
  public setForce(f: number, minf: number, maxf: number = 0) {
    this.force = f;
    this.maxForce = maxf;
    this.minForce = minf;
    if (this.force > 1.0) {
      this.force = 1.0;
    }
    if (this.maxForce > 1.0) {
      this.maxForce = 1.0;
    }
    if (this.minForce < 0) {
      this.minForce = 0;
    }
  }
  public setSpin(x: number, y: number) {
    this.spin.x = x;
    this.spin.y = y;
  }

  public updateTargetPosition(x: number, y: number) {
    this.targetPos.x = x;
    this.targetPos.y = y;
  }
}

// 自由球时，白球的位置以及信息
export class FreeKickPosition {
  public pos: Point; // 击打目标位置
  public targetPos: Point;
  public hole: DeskHole;
  public score: number; // 分值
  constructor(pos: Point, tpos: Point, hole: DeskHole, score: number = 1) {
    this.pos = pos;
    this.targetPos = tpos;
    this.hole = hole;
    this.score = score;
  }
  public updateScore(sc: number) {
    this.score = sc;
  }
}

export class AiBrainLevel {
  public aiLevel = 0;
  constructor(lv: number) {
    this.aiLevel = lv;
  }
}

export class AiGTool {
  public static radius = 0.5;

  // 两点之间是否有球遮挡
  public static hasOccluded(startp: Point, endp: Point, balls: Array<DeskBall>) {
    const minx = Math.min(startp.x, endp.x) - 2.0 * AiGTool.radius;
    const maxx = Math.max(startp.x, endp.x) + 2.0 * AiGTool.radius;
    const miny = Math.min(startp.y, endp.y) - 2.0 * AiGTool.radius;
    const maxy = Math.max(startp.y, endp.y) + 2.0 * AiGTool.radius;
    for (const ball of balls) {
      if (ball.position.x < minx || ball.position.x > maxx || ball.position.y < miny || ball.position.y > maxy) {
        continue;
      }
      const vec = startp.minus(endp);
      if (vec.norm2() < 0.1) {
        continue;
      }
      const line = new Line(startp, vec.normed());
      const dist = line.projectDistance(ball.position);
      const cossh = (startp.x - ball.position.x) * (endp.x - ball.position.x) + (startp.y - ball.position.y) * (endp.y - ball.position.y);
      if (dist < 2.1 * AiGTool.radius && cossh < 0) { // 2倍
        return true;
      }
    }
    return false;
  }

  // 三点是否共线
  public static pointOnLine(startp: Point, midp: Point, endp: Point, thres: number) {
    const vec = startp.minus(endp);
    if (vec.norm2() < 0.1) {
      return true;
    }
    const line = new Line(startp, vec.normed());
    const dist = line.projectDistance(midp);
    return dist < thres;
  }
}